import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// 一个销售 在外场 负责拉人  只有一个
// 多个销售 在内场 负责介绍  每个客户端都分配一个
public class TcpServer {

    // 拉客的销售小哥
    private ServerSocket serverSocket = null;

    public TcpServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        System.out.println("服务器启动");
        while (true) {
            // 介绍的销售小姐姐
            Socket clientSocket =
                    serverSocket.accept() /* 拉来了客人 */;
            System.out.printf("[%s %d] 客户端上线\n" , clientSocket.getInetAddress(),clientSocket.getPort());
            // 如果直接调用 , 会导致当前循环的二次执行 , 导致accep不及时 , 创建一个新的线程 , 用新线程来调用
            // 每次来一个新的客户端都搞一个新线程
//            Thread thread = new Thread(new Runnable() {
//                @Override
//                public void run() {
//                    try {
//                        processConnection(clientSocket);
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    }
//                }
//            });
//            thread.start();
            // 频繁创建线程开销大 ,所以此处使用线程池
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });


        }
    }

    // 处理连接
    // 1 - 读取请求
    // 2 - 根据请求计算响应
    // 3 - 返回响应
    private void processConnection(Socket clientSocket) throws IOException {
        // try括号允许写多个流对象,使用;分割
        // 长连接 包含多个请求 怎么分割请求 ? (约定方式并非唯一的)
        // 此处约定请求和请求之间使用\n来分割
        // 后续发送请求的时候,也要带上\n
        // 由于是回显服务器 , 响应和请求一样,也遵守上述规则
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()){
            Scanner scanner = new Scanner(inputStream); // 将字节流转换成字符流
            PrintWriter printWriter = new PrintWriter(outputStream);

            while (true) {
                // 1 - 读取请求
                if (!scanner.hasNext()) {
                    // 读取的字符流到了结尾(对端关闭了)
                    // hasNext判断接下来是否还有数据,如果对端关闭连接,则返回false
                    // 循环结束,如果有数据,就返回true,进一步可以1使用next方法来读出字符串内容
                    // 打印客户端的ip和端口
                    System.out.printf("[%s %d] 客户端下线\n",clientSocket.getInetAddress(),clientSocket.getPort());
                    break;
                }
                //        next读出的结果是不带换行的
                String request = scanner.next();
                // 2 - 计算响应
                String response = process(request);
                // 3 - 把响应写回给客户端
                //        需要把换行带上
                printWriter.println(response);
                System.out.printf("[res %s resp %s]",request,response);
                printWriter.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            clientSocket.close();
        }

    }

    private String process(String request) {
        return "1234";
    }

    public static void main(String[] args) throws IOException {
        TcpServer tcpServer = new TcpServer(9090);
        tcpServer.start();
    }
}
